package tools

import (
	"context"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/rs/zerolog/log"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	"techoiceness.com/aiagent/llm-gateway/internal/llm/types"
	"techoiceness.com/aiagent/llm-gateway/internal/repository"
)

// PostgreSQLTool PostgreSQL数据库工具
type PostgreSQLTool struct {
	repository repository.SimpleToolRepository
	db         *gorm.DB
	config     *PostgreSQLToolConfig
	configHash string       // 配置的MD5哈希，用于检测配置变更
	mutex      sync.RWMutex // 保护并发访问
}

// PostgreSQLToolConfig 新的配置格式，直接存储数据库连接信息
type PostgreSQLToolConfig struct {
	Host                string `json:"host"`
	Port                int    `json:"port"`
	Username            string `json:"username"`
	Password            string `json:"password"`
	Database            string `json:"database"`
	SSLMode             string `json:"ssl_mode,omitempty"`
	Timezone            string `json:"timezone,omitempty"`
	QueryTimeoutSeconds int    `json:"query_timeout_seconds,omitempty"`
	MaxResultRows       int    `json:"max_result_rows,omitempty"`
}

// NewPostgreSQLTool 创建PostgreSQL工具
func NewPostgreSQLTool(repository repository.SimpleToolRepository) *PostgreSQLTool {
	return &PostgreSQLTool{
		repository: repository,
	}
}

func (p *PostgreSQLTool) Name() string {
	return "postgresql"
}

func (p *PostgreSQLTool) Description() string {
	return "Execute PostgreSQL queries and retrieve data"
}

func (p *PostgreSQLTool) Definition() types.Tool {
	return types.Tool{
		Type: "function",
		ToolFunction: types.ToolFunction{
			Name:        p.Name(),
			Description: p.Description(),
			Parameters: types.JSONSchema{
				Type: "object",
				Properties: map[string]*types.JSONSchema{
					"query": {
						Type:        "string",
						Description: "The SQL query to execute (any valid SQL query)",
					},
				},
				Required: []string{"query"},
			},
		},
	}
}

type PostgreSQLToolParams struct {
	Query string `json:"query"`
}

func (p *PostgreSQLTool) Execute(arguments string) (string, error) {
	var params PostgreSQLToolParams

	if err := json.Unmarshal([]byte(arguments), &params); err != nil {
		return "", fmt.Errorf("参数解析错误: %w", err)
	}

	if strings.TrimSpace(params.Query) == "" {
		return "", fmt.Errorf("SQL语句不能为空")
	}

	// 获取数据库连接（会检查配置变更并重新连接）
	db, config, err := p.getConnection()
	if err != nil {
		return "", fmt.Errorf("获取数据库连接失败: %w", err)
	}

	var queryTimeout time.Duration
	if config.QueryTimeoutSeconds == 0 {
		queryTimeout = 30 * time.Second
	} else {
		queryTimeout = time.Duration(config.QueryTimeoutSeconds) * time.Second
	}

	var maxResultRows int
	if config.MaxResultRows == 0 {
		maxResultRows = 2000
	} else {
		maxResultRows = config.MaxResultRows
	}

	ctx, cancel := context.WithTimeout(context.Background(), queryTimeout)
	defer cancel()

	// 设置查询超时
	queryCtx, cancel := context.WithTimeout(ctx, queryTimeout)
	defer cancel()

	start := time.Now()
	var results []map[string]interface{}

	// 直接执行原始查询，不添加额外限制
	err = db.WithContext(queryCtx).Raw(params.Query).Scan(&results).Error
	duration := time.Since(start)

	// 如果结果超过配置的最大行数，截断并警告
	if len(results) > maxResultRows {
		results = results[:maxResultRows]
	}

	if err != nil {
		// 返回对大模型友好的错误信息
		return fmt.Sprintf("SQL执行错误: %s", err.Error()), nil
	}

	// 大模型只需要简洁的查询结果
	if len(results) == 0 {
		return "结果为空", nil
	}

	resultJSON, err := json.Marshal(results)
	if err != nil {
		return "", fmt.Errorf("序列化结果失败: %w", err)
	}

	log.Info().
		Str("module", "PostgreSQLTool.Execute").
		Str("query", params.Query).
		Dur("duration", duration).
		Int("result_count", len(results)).
		Msg("PostgreSQL查询执行成功")

	return string(resultJSON), nil
}

// getConnection 获取数据库连接，检查配置变更并重新连接（如果需要）
func (p *PostgreSQLTool) getConnection() (*gorm.DB, *PostgreSQLToolConfig, error) {
	p.mutex.Lock()
	defer p.mutex.Unlock()

	// 加载当前配置
	config, err := p.loadConfig()
	if err != nil {
		return nil, nil, fmt.Errorf("加载配置失败: %w", err)
	}

	// 计算配置的哈希值
	configHash := p.calculateConfigHash(config)

	// 如果配置没有变更且连接存在，直接返回现有连接
	if p.configHash == configHash && p.db != nil {
		// 测试连接是否仍然有效
		if sqlDB, err := p.db.DB(); err == nil {
			if err := sqlDB.Ping(); err == nil {
				return p.db, config, nil
			}
		}
		log.Info().
			Str("module", "PostgreSQLTool.getConnection").
			Msg("数据库连接失效，重新建立连接")
	}

	// 关闭旧连接
	if p.db != nil {
		if sqlDB, err := p.db.DB(); err == nil {
			sqlDB.Close()
		}
	}

	// 建立新连接
	db, err := p.createDatabaseConnection(config)
	if err != nil {
		return nil, nil, fmt.Errorf("创建数据库连接失败: %w", err)
	}

	// 更新缓存
	p.db = db
	p.config = config
	p.configHash = configHash

	log.Info().
		Str("module", "PostgreSQLTool.getConnection").
		Str("config_hash", configHash).
		Msg("PostgreSQL工具连接已建立")

	return db, config, nil
}

// calculateConfigHash 计算配置的MD5哈希值
func (p *PostgreSQLTool) calculateConfigHash(config *PostgreSQLToolConfig) string {
	configJSON, _ := json.Marshal(config)
	hash := md5.Sum(configJSON)
	return hex.EncodeToString(hash[:])
}

// ReloadConfig 强制重新加载配置（由tool manager调用）
func (p *PostgreSQLTool) ReloadConfig() error {
	p.mutex.Lock()
	defer p.mutex.Unlock()

	// 关闭现有连接
	if p.db != nil {
		if sqlDB, err := p.db.DB(); err == nil {
			sqlDB.Close()
		}
		p.db = nil
	}

	// 清空配置缓存，下次执行时会重新加载
	p.config = nil
	p.configHash = ""

	return nil
}

// loadConfig 从数据库加载工具配置
func (p *PostgreSQLTool) loadConfig() (*PostgreSQLToolConfig, error) {
	if p.repository == nil {
		return nil, fmt.Errorf("repository not available")
	}

	// 从数据库获取工具配置
	toolEntity, err := p.repository.GetToolByName(context.Background(), "postgresql")
	if err != nil {
		return nil, fmt.Errorf("无法获取工具配置: %w", err)
	}

	if toolEntity.Config == nil {
		return nil, fmt.Errorf("工具配置未初始化")
	}

	// 尝试解析新格式的配置
	var config PostgreSQLToolConfig
	if err := json.Unmarshal([]byte(*toolEntity.Config), &config); err != nil {
		return nil, fmt.Errorf("配置格式错误: %w", err)
	}

	// 验证必需的配置项
	if config.Host == "" {
		return nil, fmt.Errorf("缺少主机地址配置")
	}
	if config.Username == "" {
		return nil, fmt.Errorf("缺少用户名配置")
	}
	if config.Database == "" {
		return nil, fmt.Errorf("缺少数据库名配置")
	}

	// 设置默认值
	if config.Port == 0 {
		config.Port = 5432
	}
	if config.SSLMode == "" {
		config.SSLMode = "disable"
	}
	if config.Timezone == "" {
		config.Timezone = "UTC"
	}

	return &config, nil
}

// createDatabaseConnection 根据配置创建数据库连接
func (p *PostgreSQLTool) createDatabaseConnection(config *PostgreSQLToolConfig) (*gorm.DB, error) {
	dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s TimeZone=%s",
		config.Host, config.Port, config.Username, config.Password, config.Database, config.SSLMode, config.Timezone)

	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
	if err != nil {
		return nil, fmt.Errorf("无法连接到数据库: %w", err)
	}

	return db, nil
}
